Param()  # No parameters for now

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'


# -------------------------------
# Shared: Header generation function
# -------------------------------
function New-BuildIdHeader {
    param(
        [Parameter(Mandatory=$true)][string]$GitHash,
        [Parameter(Mandatory=$true)][string]$TimeStamp,   # yyyy.M.d.HH:mm:ss
        [Parameter(Mandatory=$true)][bool]$Dirty,
        [string]$OutDir = 'generated'
    )

    # Strip any CR/LF and outer whitespace
    $GitHash   = ($GitHash -replace '[\r\n]+','').Trim()
    $TimeStamp = ($TimeStamp -replace '[\r\n]+','').Trim()

    # Defensive: if GitHash is empty, use "unknown"
    if ([string]::IsNullOrWhiteSpace($GitHash)) { $GitHash = 'unknown' }

    # Short hash
    $gitHashShort = if ($GitHash.Length -ge 7) { $GitHash.Substring(0,7) } else { $GitHash }

    # Literal true/false without quotes
    $dirtyToken = if ($Dirty) { 'true' } else { 'false' }

    if (-not (Test-Path -LiteralPath $OutDir)) {
        New-Item -ItemType Directory -Path $OutDir | Out-Null
    }

    $content = @"
#pragma once
// Auto-generated by build_id_gen.ps1

#define PM_BID_GIT_HASH "$GitHash"
#define PM_BID_GIT_HASH_SHORT "$gitHashShort"
#define PM_BID_TIME "$TimeStamp"
#define PM_BID_UID "$GitHash-$TimeStamp"
#define PM_BID_DIRTY $dirtyToken
"@

    # Write (overwrite) the file
    $outFile = Join-Path $OutDir 'build_id.h'
    Set-Content -LiteralPath $outFile -Value $content
}



##########################
# main routine start

# Ensure the "generated" folder exists
if (-not (Test-Path -LiteralPath 'generated')) {
    New-Item -ItemType Directory -Path 'generated' | Out-Null
}

# -------------------------------
# vcpkg short-circuit
# -------------------------------
$inVcpkg = ($env:PM_VCPKG_MODE -eq '1')
if ($inVcpkg) {
    Write-Host "[build_id_gen] vcpkg mode detected."

    # Choose which identifier to expose as 'hash' in vcpkg builds.
    # Prefer the upstream ref/commit if provided; fall back to tarball SHA512 or 'unknown'.
    $gitHash = @($env:PM_VCPKG_REF, $env:PM_VCPKG_SHA512, 'BADF00D5') |
               Where-Object { $_ -and $_.Trim() -ne '' } |
               Select-Object -First 1
    $gitHash = $gitHash.Trim()

    # Build time; use UTC if you prefer: (Get-Date).ToUniversalTime().ToString('yyyy.M.d.HH:mm:ss')
    $timeStamp = Get-Date -Format 'yyyy.M.d.HH:mm:ss'

    # Always clean for vcpkg builds
    New-BuildIdHeader -GitHash $gitHash -TimeStamp $timeStamp -Dirty:$false -OutDir 'generated'
    return
}


# ------------------------------------------------------------------------------
# 1) CAPTURE SIGNATURE A (LIST OF UNCOMMITTED CHANGES WITH LINES ADDED/REMOVED)
# ------------------------------------------------------------------------------
Write-Host "[build_id_gen] Gathering diff info (Signature A)..."

# 1A1) Sig A always starts with the git commit hash
$signatureA_current_lines = ((git rev-parse HEAD) | Out-String).Trim()

# 1A2) Normal 'numstat' lines for tracked changes
$signatureA_current_lines += git diff --numstat

# 1B) Collect untracked files so we can treat them like "newly added"
#     (i.e., lines = total lines, removed = 0)
$untrackedFiles = git ls-files --others --exclude-standard

foreach ($uf in $untrackedFiles) {
    # Ensure file still exists (and isn't a folder)
    if (Test-Path $uf) {
        # Count lines. If the file is huge or binary, consider try/catch or skip.
        $lineCount = (Get-Content $uf -ErrorAction SilentlyContinue | Measure-Object -Line).Lines

        # Append path to make relative to solution (repo) root
        $uf = 'IntelPresentMon/Versioning/' + $uf

        # Append a "numstat-like" line: "<lines> 0 <filePath>"
        # Use backtick-t (`t) for tabs, to mirror git diff --numstat output.
        $signatureA_current_lines += "$lineCount`t0`t$uf"
    }
}

# 1C) Build a single signature string (space-separated or however you like).
#     If you want each record separated by a newline instead, use "-join [Environment]::NewLine"
$signatureA_current = $signatureA_current_lines -join ' '

# Retrieve previous signature A if it exists
$signatureA_prev = ''
if (Test-Path 'generated\signature_a_prev.txt') {
    $signatureA_prev = Get-Content 'generated\signature_a_prev.txt' -Raw
}

# ------------------------------------------------------------------------------
# 2) CAPTURE SIGNATURE B (PER-FILE MD5 FOR ALL UNCOMMITTED FILES)
# ------------------------------------------------------------------------------
Write-Host "[build_id_gen] Calculating per-file hashes (Signature B)..."
$signatureB_current = ''

foreach ($line in $signatureA_current_lines) {
    # Each line is something like: 10  2  src\main.cpp
    # Split on whitespace
    $fields = $line -split '\s+'
    if ($fields.Count -ge 3) {
        $linesAdded   = $fields[0]
        $linesRemoved = $fields[1]
        $changedFile  = '../../' + $fields[2]

        # Edge case: file might be deleted or not present
        if (-not (Test-Path $changedFile)) {
            # Write-Host "[build_id_gen] File '$changedFile' does not exist (possibly deleted). Skipping..."
            continue
        }

        # Get MD5 hash of the file
        # (You can change -Algorithm to e.g. SHA256 if desired)
        $hash = (Get-FileHash $changedFile -Algorithm MD5).Hash
        $signatureB_current += $hash
    }
}

# Retrieve previous signature B if it exists s
$signatureB_prev = ''
if (Test-Path 'generated\signature_b_prev.txt') {
    $signatureB_prev = Get-Content 'generated\signature_b_prev.txt' -Raw
}

# if the generated header is missing we must regenerate    
if (-not (Test-Path 'generated\build_id.h')) {
    Write-Host "[build_id_gen] Versioning\generated\build_id.h not present; generating..."
    # Store signature A and B since we don't know if they have changed
    $signatureA_current | Set-Content 'generated\signature_a_prev.txt'
    $signatureB_current | Set-Content 'generated\signature_b_prev.txt'
}
else {
    # If Signature A is unchanged, we must check Signature B
    if ($signatureA_current.Trim() -eq $signatureA_prev.Trim()) {
        # If Signature B is also unchanged, skip generating build_id.h
        if ($signatureB_current.Trim() -eq $signatureB_prev.Trim()) {
            Write-Host "[build_id_gen] Signature B is unchanged. Skipping Versioning\generated\build_id.h regeneration."
            return
        }    
        # Store the updated Signature B
        $signatureB_current | Set-Content 'generated\signature_b_prev.txt'
        Write-Host "[build_id_gen] Signature B mismatch detected."
    } else {
        # Store the updated Signature A (and B, since it may have also changed)
        $signatureA_current | Set-Content 'generated\signature_a_prev.txt'
        $signatureB_current | Set-Content 'generated\signature_b_prev.txt'
        Write-Host "[build_id_gen] Signature A mismatch detected."
    }
}


# ------------------------------------------------------------------------------
# 3) GENERATE/UPDATE BUILD_ID.H
# ------------------------------------------------------------------------------
Write-Host "[build_id_gen] Generating new build_id.h..."

# Get the current git commit hash
$gitHash       = (git rev-parse HEAD)        | Out-String

# Format: yyyy.M.d.HH:mm:ss (e.g., 2025.1.8.12:20:11)
$dateTime = Get-Date -Format 'yyyy.M.d.HH:mm:ss'

# Uncommitted detection (your original)
git diff --quiet
$dirty = -not ($LASTEXITCODE -eq 0)

New-BuildIdHeader -GitHash $gitHash -TimeStamp $dateTime -Dirty:$dirty -OutDir 'generated'